﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EditoneLib.Streams.Audio
{
    public class NormalizeStream : ReadonlyStream
    {
        private Stream _sourceStream;
        private float _coef = 0.000001f;

        public NormalizeStream(Stream sourceStream)
        {
            _sourceStream = sourceStream;
            GetCoefficient();
        }

        private void GetCoefficient()
        {
            var buffer = new byte[192000];
            var floatBuffer = new float[48000];

            int count;
            lock (_sourceStream)
            {
                _sourceStream.Position = 0;
                while ((count = _sourceStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    int floatCount = count/sizeof(float);
                    Buffer.BlockCopy(buffer, 0, floatBuffer, 0, count);
                    for (var i = 0; i < floatCount; i++)
                    {
                        var value = floatBuffer[i];
                        if (Math.Abs(value) > _coef)
                        {
                            _coef = Math.Abs(value);
                        }
                    }
                }
            }
            Position = 0;
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            var sourceBuffer = new byte[192000];
            var floatBuffer = new float[48000];
            int byteCount = _sourceStream.Read(sourceBuffer, 0, count);
            int floatCount = byteCount / sizeof(float);
            Buffer.BlockCopy(sourceBuffer, 0, floatBuffer, 0, byteCount);
            for (var i = 0; i < floatCount; i++)
            {
                floatBuffer[i] /= _coef;
            }
            Buffer.BlockCopy(floatBuffer, 0, buffer, offset, floatCount * sizeof(float));
            return floatCount * sizeof(float);
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            return _sourceStream.Seek(offset, origin);
        }

        public override long Length
        {
            get { return _sourceStream.Length; }
        }

        public override long Position
        {
            get { return _sourceStream.Position; }
            set { _sourceStream.Position = value; }
        }
    }
}
